package com.sam.mybatisplus.support.aspect;

import cn.hutool.core.util.ObjectUtil;
import com.sam.common.Result;
import com.sam.common.utils.DateTool;
import com.sam.common.utils.ReflectionUtils;
import com.sam.mybatisplus.support.annotation.ConvertDateTimeZone;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.TimeZone;

/**
 * @classname: ConvertDateTimeZoneAspect
 * @description: 日期时间转换
 * @Author: sam
 * @date: 2021/4/27 11:37
 */
@Slf4j
@Aspect
@Component
public class ConvertDateTimeZoneAspect3 {

    String currTimeZoneId="Asia/Shanghai";

    String tagerTimeZoneId="Europe/London";

    @Pointcut("execution(public * com.sam.mybatisplus.controller..*.*(..))")
    public void methodPoint(){}

    @Around("methodPoint()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //得到拦截的方法
        Method method = signature.getMethod();
        //获取方法参数注解，返回二维数组是因为某些参数可能存在多个注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        // 获取所有参数值
        Object[] paramValues = joinPoint.getArgs();
        //获取方法参数名
        String[] paramNames = signature.getParameterNames();

        // 没有入参的请求
        if (paramNames.length==0) {
            Object returnValue = joinPoint.proceed();
            handleReturnValue(returnValue,tagerTimeZoneId);
            return returnValue;
        }
        // 处理单个参数
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (int j = 0; j < parameterAnnotations[i].length; j++) {
                Annotation annotation = parameterAnnotations[i][j];
                if (annotation instanceof ConvertDateTimeZone){
                    String paramName = paramNames[i];
                    Object paranValue = paramValues[i];
                    String pattern = ((ConvertDateTimeZone) annotation).pattern();
                    String currTimeZoneId = TimeZone.getDefault().getID();
                    if (paranValue instanceof String){
                        String dateTime = (String)paranValue;
                        paramValues[i] = DateTool.timeZoneTransfer(dateTime, pattern, currTimeZoneId,tagerTimeZoneId);
                    }
                    if (paranValue instanceof Date){
                        Date dateTime = (Date)paranValue;
                        paramValues[i] = DateTool.timeZoneTransfer(dateTime,currTimeZoneId,tagerTimeZoneId);
                    }
                }
            }
        }
        // 处理bean参数
        for (int i=0;i<paramNames.length;i++){
            Object paramValue = paramValues[i];
            if (Objects.isNull(paramValue)){
                continue;
            }
            recursion(paramValue,currTimeZoneId,tagerTimeZoneId);
        }

        Object returnValue  = joinPoint.proceed(paramValues);
        // 处理返回值
        handleReturnValue(returnValue,tagerTimeZoneId);
        return returnValue ;
    }
    /**
     * 递归处理时区
     */
    private void recursion(Object object,String currTimeZoneId,String tagerTimeZoneId){
        if (ObjectUtil.isEmpty(object)){
            return;
        }
        if (!isPrimitive(object)) {
            Class<?> clazz = object.getClass();
            String packageName = object.getClass().getPackage().getName();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                // 获取属性的类型
                String type = field.getGenericType().toString();
                Object fieldValue = ReflectionUtils.getFieldValue(object, field.getName());
                if (ObjectUtil.isEmpty(fieldValue)){
                    continue;
                }
                if (type.contains("List")) {
                    //log.debug("处理返回值为list类型的数据");
                    List<Object> dataList = (List<Object>) fieldValue;
                    for (Object obj : dataList) {
                        recursion(obj, currTimeZoneId, tagerTimeZoneId);
                    }
                }else if (type.equals("class java.lang.String")){
                    // 处理返回单个对象类型，判断此对象中是否有添加需要处理时区的注解
                    ConvertDateTimeZone annotation = field.getAnnotation(ConvertDateTimeZone.class);
                    if (annotation==null){
                        continue;
                    }
                    // 格式
                    String pattern = annotation.pattern();
                    // 将此字段强制变为可修改
                    field.setAccessible(true);
                    if (fieldValue==null){
                        continue;
                    }
                    String dateTime = (String)fieldValue;
                    fieldValue=DateTool.timeZoneTransfer(dateTime,pattern,currTimeZoneId,tagerTimeZoneId);
                    log.debug("处理String类型转换时区,field:{} value:{} convert to {}",field.getName(),dateTime,fieldValue);
                    ReflectionUtils.setFieldValue(object,field.getName(),fieldValue);
                }else if (type.equals("class java.util.Date")){
                    // 处理返回单个对象类型，判断此对象中是否有添加需要处理时区的注解
                    ConvertDateTimeZone annotation = field.getAnnotation(ConvertDateTimeZone.class);
                    if (annotation==null){
                        continue;
                    }
                    // 格式
                    String pattern = annotation.pattern();
                    // 将此字段强制变为可修改
                    field.setAccessible(true);
                    Date dateTime = (Date)fieldValue;
                    fieldValue=DateTool.timeZoneTransfer(dateTime,currTimeZoneId,tagerTimeZoneId);
                    log.debug("处理Date类型转换时区,field:{} value:{} convert to {}",field.getName(),dateTime,fieldValue);
                    ReflectionUtils.setFieldValue(object,field.getName(),fieldValue);
                }else if (packageName.contains("com.iukos")){
                    recursion(fieldValue, currTimeZoneId, tagerTimeZoneId);
                }
            }
        }
    }

    /**
     * 处理方法返回值
     * @param returnValue
     */
    private void handleReturnValue(Object returnValue,String timeZoneId){
        log.debug("处理响应参数");
        if (returnValue instanceof Result){
            Result result = (Result) returnValue;
            Object data = result.getData();
            recursion(data,currTimeZoneId,tagerTimeZoneId);
        }
    }

    /**判断一个对象是否是基本类型或基本类型的封装类型*/
    private boolean isPrimitive(Object obj) {
        try {
            return ((Class<?>)obj.getClass().getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }
}
